<?php
//DI  主要运用IoC用于解决 依赖文件共享（无需每一个依赖都手动注册）

//管理应用程序中的『全局』对象（包括实例化、处理依赖关系）。
//可以延时加载对象（仅用到时才创建对象）。
//促进编写可重用、可测试和松耦合的代码。

class di{
    private $_definitions=[]; //保存依赖定义
    private $_dependencies=[]; //保存依赖信息
    private $_singletons=[]; //用于保存单例
    private $_reflections=[]; //用于缓存（依赖）实例
    private $_params=[]; //保存构造函数的参数
    
    public function set($class, $dependencies=[], $params=[]){
        //注册一个类 声明它的 类名、依赖类、构造实例的参数
        $this->_definitions[$class] = $class;
        $this->_dependencies[$class] = $dependencies;
        $this->_params[$class] = $params;
    }
    
    /***
      * 创建依赖实例方法
      * $class 创建实例的类名 
      * $params 创建实例的依赖参数
      * $config 创建实例的配置
    ***/
    public function build($class,$params=[],$config=[]){
        //验证依赖--递归创建
        $this->validate($class);
        
        //将实例化的类储存到 公用类库
        $this->_reflections[$class]=new $class($this->validate_create($class));
    }
    public function get($class,$config=[]){
        //验证依赖--递归创建
        $this->validate($class);
        //最终返回结果
        return new $class($this->validate_create($class));
    }
    
    //用于验证依赖并创建
    public function validate($class,$params=[],$config=[]){
        if(isset($this->_dependencies[$class])){
            //是否存在依赖信息--如果存在创建新对象 储存到库
            foreach($this->_dependencies[$class] as $v){
                $this->build($v);//创建依赖
            }
        }
    }
    //最终创建对象前 验证参数配置并构成
    public function validate_create($class){
        $arr=[];
        //判断是否存在依赖属性
        if(isset($this->_params[$class])){
        //将类名和的依赖类 对应
            foreach($this->_params[$class] as $v){
                //从公共库取出实例加入参数
                $arr[$v]=$this->_reflections[$v];
            }
        }
        return $arr;
    }
    
}



//测试类
class test{
    protected $_word;
    protected $_else;
    
    public function __construct($class){
        foreach($class as $k=>$v){
            if($v instanceof jk1){
                $this->_word=$v;
            }elseif($v instanceof jk2){
                $this->_else=$v;
            }
        }
    }
    
    public function say1(){
        $this->_word->jk1_say();
    }
    public function say2(){
        $this->_else->jk2_say();
    }
}

//定义两个依赖接口
interface jk1{
     public function jk1_say();
}

interface jk2{
     public function jk2_say();
}

//两个例子
class my_jk1 implements jk1{
    protected $obj;
    public function __construct($class){
        foreach($class as $k=>$v){
            $this->obj = $v;
        }
    }
    public function jk1_say(){
        echo $this->obj->abc();
    }
}

class my_jk2 implements jk2{
    public function jk2_say(){
        echo __METHOD__;
    }
}

//my_jk1的依赖
class my_jk1_ext{
    public function abc(){
        echo __METHOD__;
    }
}




$di = new di;
$di->set('my_jk1', ['my_jk1_ext'], ['my_jk1_ext']);//添加关系
$di->set('test', ['my_jk1', 'my_jk2'], ['my_jk1', 'my_jk2']);


$a = $di->get('test');
$a->say1();
echo "<hr>";
$a->say2();